<?php

namespace AgilePayments;

use GuzzleHttp\Client;

/**
 * @desc 工具类
 */
class Tool
{
    public static $data;

    /**
     * @desc 获取env文件变量
     * @param $name string 变量名称
     * @param $default any 默认值
     * @param $showParent bool 是否显示父类数组
     * @return mixed|null
     */
    public static function env($name,$default = null, $showParent = false)
    {
        $path = dirname(__DIR__,'4') . DIRECTORY_SEPARATOR . '.env';
        if (file_exists($path)){
            $env = parse_ini_file($path, true, INI_SCANNER_RAW) ?: [];
            $env = array_change_key_case($env, CASE_UPPER);
            foreach ($env as $key => $val) {
                if ($showParent){
                    self::$data[$key] = $val;
                }
                if (is_array($val)) {
                    foreach ($val as $k => $v) {
                        self::$data[$key . '_' . strtoupper($k)] = $v;
                    }
                } else {
                    self::$data[$key] = $val;
                }
            }
            $key = strtoupper(str_replace('.','_',$name));
            return self::$data[$key] ?? $default;
        }else{
            return $default;
        }

    }


    /**
     * @desc 发送钉钉机器人消息（验签方法）
     */
    public static function dingSend($message = '',$code = '', $expire = 3600)
    {
        if (is_array($message)){
            $message = implode("\r\n",$message);
        }
        if ($message == ''){return false;}

//        todo 控制同一信息时间间隔 redis初始化失败问题之后解决
//        $redis = new \Redis();
//        $redis->connect(self::env('redis.host','127.0.0.1'), (int)self::env('redis.port','6379'));
//
//        if ($code != ''){
//            if ($redis->get('dingSend_'.$code) !== false){
//                return false;
//            }else{
//                $redis->setex('dingSend_'.$code, $expire, $code);
//            }
//        }
        // 加签
        $token = Tool::env('dingSendSign.token','82447c787740a9a37a7debc1f8064060a593991028ff22d13b6fede95e861cc6');    // 机器人的token
        $secret = Tool::env('dingSendSign.secret','SEC9afdcdbe52cfa200d8fc0fcf8acef3d64037c47452188f1684ba364edbcdf138');   // 钉钉给出的密钥
        // 获取微秒数时间戳
        list($s1, $s2) = explode(' ', microtime());
        // 转换成毫秒数时间戳
        $msectime = (float)sprintf('%.0f', (floatval($s1) + floatval($s2)) * 1000);
        // 拼装成待加密字符串
        // 格式：毫秒数+"\n"+密钥
        $stringToSign = $msectime . "\n" . $secret;
        // 进行加密操作 并输出二进制数据
        $sign = hash_hmac('sha256', $stringToSign, $secret, true);
        // 加密后进行base64编码 以及url编码
        $sign = urlencode(base64_encode($sign));
        // 拼接url
        $url = 'https://oapi.dingtalk.com/robot/send?access_token=' . $token;
        $url .= '&timestamp=' . $msectime; // 拼接时间戳
        $url .= '&sign=' . $sign;         // 拼接加密签名
        try {
            return  self::dingtalk_by_curl($url, $message);
        }catch (Exception $exception){
            self::log($exception->getMessage(),'error');
        }
    }

    /**
     * 发送消息
     */
    private static function dingtalk_by_curl($url, $message)
    {
        $client = new Client();
        $data = [
            'verify' => false,
            'json' => [
                'msgtype' => 'text',
                'text' => [
                    'content' => $message
                ],
            ],
            'headers' => [
                'Content-Type' => 'application/json',
                'charset' => 'utf-8',
            ],
        ];
        $res = $client->request('POST', $url, $data)->getBody()->getContents();
        $res = json_decode($res, true);
        return $res;
    }

    /**
     * 自定义日志记录 （可以在。env的agile_payments.log_path层级下配置本目录 默认：../runtime/log/agile_payments/）
     * @param string|array    $data  记录内容
     * @param string $type  记录的方式
     * @param string $path  添加最后一级路径（默认没有）
     * @return void
     */
    public static function log($data, string $type = 'notice', string $path = '', bool $is_full_path = false)
    {
        $execInfo = debug_backtrace();
        $dividingLine = '------------------------------------------------------------------------------------------------------------------------';
        $date = date('Y-m-d H:i:s');
        $header = $dividingLine . PHP_EOL . "[ $type ] [ $date ] [{$execInfo[0]['file']}:{$execInfo[0]['line']}] " . PHP_EOL;
        if ($path == ''){
            $path = self::getRootPath() . './runtime/log/agile_payments/' . date('Ymd') . DIRECTORY_SEPARATOR;
        }else{
            if ($is_full_path){
                $path = $path . DIRECTORY_SEPARATOR . date('Ymd') . DIRECTORY_SEPARATOR;
            }else{
                $path = self::getRootPath() . './runtime/log/agile_payments/' . $path . DIRECTORY_SEPARATOR . date('Ymd') . DIRECTORY_SEPARATOR;
            }
        }
        if (!is_dir($path)){
            mkdir($path,0777,true);
        }
        $file_name = $path . date('YmdH') . '.log';
        error_log( $header . '{ INFO }' . PHP_EOL  . print_r($data,true) . PHP_EOL  .  '{ DATA }' . PHP_EOL  . var_export($data,true) . PHP_EOL, 3, $file_name);
    }

    /**
     * 生成订点号
     * @desc  20 长度 0.8秒生成50000个重复个数20以下(字符长度越长，重复率越低)
     * @param $prefix string  前缀 (最长不超过5个)
     * @param $length int 返回长度
     * @return string
     * @throws \Exception
     */
    public static function createOrderNo($prefix = 'ORDER', $length = 20): string
    {
        if ($length-strlen($prefix) < 15){throw new \Exception('创建订单号前缀不能太长');}
//        if (strlen($prefix) > 5 && $length < 30){throw new \Exception('创建订单号前缀不能超过5个');}
        if ($length < 20){throw new \Exception('订单号长度不能小于20');}
        $time = base_convert(time(),10, 36); // 6位
        $head = $prefix . strlen($prefix) . $time ;
        $rand_num = $length - strlen($head);
        $rand_str = '';
        for ($i = bcadd(bcdiv($rand_num,3),1); $i > 0; $i--){
            $rand_str .= rand(111,999);
        }
        return mb_strtoupper(substr($head . $rand_str , 0, $length));
    }

    /**
     * @desc PHP输入网页表格
     * @param $head array 表格标题【一维数组】
     * @param $body array 表格数据【二维数组】
     * @param $title string 页面标题
     * @return void
     */
    public static function echoHtmlTable($head = ['a','b'], $body = [[1,2]], $title = '输入页面')
    {
        $headStr = '';
        $bodyStr = '';
        foreach ($head as $v){
            $headStr .= "<th>$v</th>";
        }
        foreach ($body as $v){
            $bodyStr .= '<tr>';
            foreach ($v as $value){
                $bodyStr .= "<td>$value</td>";
            }
            $bodyStr .= '</tr>';
        }
//        <tr>
//            <td>张三</td>
//            <td>12</td>
//            <td>湖北武汉</td>
//            <td>13540021458</td>
//            <td>湖北省武汉市</td>
//          </tr>
        $html = <<<HTML
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>$title</title>
    <style>
      * {
        padding: 0;
        margin: 0;
      }
      html, body {
        width: 100%;
        height: 100%;
      }
      .table {
        width: 100%;
        /*为表格设置合并边框属性*/
        border-collapse: collapse;
      }
      .table tr th, .table tr td {
        margin: 0;
        padding: 15px 16px 14px;
        box-sizing: border-box;                                                                                                 
      }
      .table thead th {
        background: #fafafa;
      }
      .table tr th {
        background: #fafafa;
        transition: background .3s ease;
        text-align: left;
        color: rgba(0, 0, 0, 0.85);
        font-weight: 500;
        border-bottom: 1px solid #e8e8e8;
      }
      .table tr td {
          border-bottom: 1px solid #e8e8e8;
          transition: all .3s;
      }
      .table>tbody>tr:hover {
          background: #e9f5fe;
      }
      .fixedTableHeader {
        width: calc(100% - 40px);
        display: none;
        position: fixed;
        top: 0px;
        left: 20px;
        overflow: hidden;
        margin: 0 auto;
        z-index: 999;
        transition: all 0.5s ease-in;
      }
    </style>
  </head>
  <body>
    <div style="padding: 20px;">
      <div id="fixedTableHeader" class="fixedTableHeader">
          <table class="table">
              <thead>
                <tr id="mytr1">
                    $headStr
                </tr>
              </thead>
            </table>
      </div>
      <div>
        <table id="table" class="table">
        <thead>
          <tr id="mytr2">
          $headStr
          </tr>
        </thead>
        <tbody>
            $bodyStr
         </tbody>
      </table>
      </div>
    </div>
  </body>
  <script type="text/javascript">
    const mytr1Child = document.getElementById('mytr1').children;
    const mytr2Child = document.getElementById('mytr2').children;
    const table = document.getElementById('table');
    const fixedTableHeader = document.getElementById('fixedTableHeader')
    // 设置隐藏表头每一列的宽度和实际表头每一列的宽度保持一致
    function setWidth() {
      for(let i = 0; i < mytr1Child.length; i++) {
        mytr1Child[i].style.width = mytr2Child[i].offsetWidth + 'px';
      }
    }
    setWidth();
    window.resize = function() {
      setWidth();
    }
    document.addEventListener('scroll', () => {
      if(document.documentElement.scrollTop > table.offsetTop) {
        fixedTableHeader.style.display = 'block';
      } else {
        fixedTableHeader.style.display = 'none';
      }
    });
  </script>
</html>
HTML;
        echo $html;

    }

    /**
     * @param $msg string 消息
     * @param $type string|int 颜色 [error,success,warning,info] or [0~107]
     * @return string
     */
    public static function cmdMsg($msg = '', $type = ''){
        if(substr(php_sapi_name(), 0, 3) != 'cgi'){
            // 命令行运行
            if (is_string($type)){
                switch ($type){
                    case 'error':
                        $startCode = "\033[31m";
                        break;
                    case 'success':
                        $startCode = "\033[32m";
                        break;
                    case 'warning':
                        $startCode = "\033[33m";
                        break;
                    case 'info':
                    default:
                        $startCode = "\033[0m";
                        break;

                }
            }
            if (is_numeric($type)){
                $startCode = "\033[{$type}m";
            }
            $endCode = "\033[0m";

        }else{
//            $startCode = '<font color="red">';
//            $endCode = '</font>';
            $startCode = '';
            $endCode = '';
        }
        return "{$startCode}{$msg}{$endCode}";
    }
    /**
     * @desc 命令行进度条
     * @param int $i 进度【0,100】
     * @return string
     */
    public static function cmdProgresBar(int $i)
    {
        $i = ceil(bcdiv($i,2));
        $str1 = '';
        for ($j=$i;$j>0;$j--){
            $str1 .= '=';
        }
        $num = bcmul($i,2);
        $num = str_pad($num, 3, " ", STR_PAD_LEFT);
        $str = "[                      {$num}%                        ]";
        $str = substr_replace($str,$str1,1,$i);
        $str = substr_replace($str,$num.'% ',24,5);
        return "\033[55D".$str;
    }

    public static function getRootPath()
    {
        return dirname(__DIR__,'4') . DIRECTORY_SEPARATOR;
    }
}